# frozen_string_literal: true

require_relative '../../../../spec_helper'

describe Wpxf::Option do
  let(:attrs) { { name: 'test', desc: 'desc' } }
  let(:subject) { Wpxf::Option.new(attrs) }

  describe '#new' do
    context 'when none or minimal attributes are specified' do
      it 'raises an error if name and desc aren\'t specified' do
        message = 'A value must be specified for :name and :desc'
        expect { Wpxf::Option.new({}) }.to raise_error message
      end

      it 'assigns a default value of false if required isn\'t specified' do
        expect(subject.required).to be false
      end

      it 'assigns a default value of false if advanced isn\'t specified' do
        expect(subject.advanced).to be false
      end

      it 'assigns a default value of false if evasion isn\'t specified' do
        expect(subject.evasion).to be false
      end
    end

    context 'when a valid set of attributes are specified' do
      let(:attrs) do
        {
          name: 'test',
          desc: 'desc',
          required: true,
          default: 'default',
          advanced: true,
          evasion: true,
          enums: [1, 2, 3],
          regex: /[0-9]/
        }
      end

      it 'assigns the attrs specified to their matching attr in the object' do
        expect(subject.name).to eq attrs[:name]
        expect(subject.desc).to eq attrs[:desc]
        expect(subject.required).to eq attrs[:required]
        expect(subject.default).to eq attrs[:default]
        expect(subject.advanced).to eq attrs[:advanced]
        expect(subject.evasion).to eq attrs[:evasion]
        expect(subject.enums).to eq attrs[:enums]
        expect(subject.regex).to eq attrs[:regex]
      end
    end
  end

  describe '#update_optional_attributes' do
    it 'sets the value of the optional attributes' do
      subject.update_optional_attributes(
        required: true,
        default: 'default',
        advanced: true,
        evasion: true,
        enums: [1, 2, 3],
        regex: %r{/[0-9]/}
      )

      expect(subject.required).to eq true
      expect(subject.default).to eq 'default'
      expect(subject.advanced).to eq true
      expect(subject.evasion).to eq true
      expect(subject.enums).to eq [1, 2, 3]
      expect(subject.regex).to eq %r{/[0-9]/}
    end
  end

  describe '#advanced?' do
    it 'returns a boolean' do
      expect([true, false]).to include subject.advanced?
    end

    it 'returns the value of the advanced attribute' do
      expect(subject.advanced?).to be false
    end
  end

  describe '#evasion?' do
    it 'returns a boolean' do
      expect([true, false]).to include subject.evasion?
    end

    it 'returns the value of the evasion attribute' do
      expect(subject.evasion?).to be false
    end
  end

  describe '#required?' do
    it 'returns a boolean' do
      expect([true, false]).to include subject.required?
    end

    it 'returns the value of the required attribute' do
      expect(subject.required?).to be false
    end
  end

  describe '#valid?' do
    context 'when an option isn\'t required' do
      it 'returns true if the value is nil' do
        expect(subject.valid?(nil)).to be true
      end

      it 'returns true if the value is empty' do
        expect(subject.valid?('')).to be true
      end
    end

    context 'when an option is required' do
      let(:attrs) { { name: 'test', desc: 'desc', required: true } }

      it 'returns false if the value is nil' do
        expect(subject.valid?(nil)).to be false
      end

      it 'returns false if the value is empty' do
        expect(subject.valid?('')).to be false
      end
    end

    context 'when a validation regex is specified' do
      let(:attrs) { { name: 'test', desc: 'desc', regex: /^[0-9]$/ } }

      it 'returns true if the value matches the pattern' do
        expect(subject.valid?('4')).to be true
      end

      it 'returns false if the value doesn\'t match the pattern' do
        expect(subject.valid?('invalid')).to be false
      end
    end
  end

  describe '#empty?' do
    it 'returns true if the value is nil' do
      expect(subject.empty?(nil)).to be true
    end

    it 'returns true if the value equals an empty string' do
      expect(subject.empty?('')).to be true
    end

    it 'returns false if a value is passed' do
      expect(subject.empty?('has value')).to be false
    end
  end

  describe '#value?' do
    it 'returns true if a non-empty value is specified' do
      expect(subject.value?('has value')).to be true
    end

    it 'returns false if an empty value is specified' do
      expect(subject.value?(nil)).to be false
    end
  end

  describe '#empty_required_value?' do
    it 'returns false if the option is not required' do
      expect(subject.empty_required_value?(nil)).to be false
    end

    context 'when the option is required' do
      let(:attrs) { { name: 'test', desc: 'desc', required: true } }

      it 'returns true if the value is empty' do
        expect(subject.empty_required_value?(nil)).to be true
      end

      it 'returns false if a value is specified' do
        expect(subject.empty_required_value?('test')).to be false
      end
    end
  end

  describe '#normalize' do
    it 'returns the normalized value' do
      expect(subject.normalize('test')).to eq 'test'
    end
  end

  describe '#display_value' do
    it 'returns a string' do
      expect(subject.display_value(9)).to be_a String
    end

    it 'returns a user-friendly string of the specified value' do
      expect(subject.display_value(9)).to eq 9.to_s
    end
  end
end
